home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / crudetype / version3 / w2c-ext.c < prev    next >
C/C++ Source or Header  |  1991-11-28  |  16KB  |  629 lines

  1. /* External procedures for these programs.  */
  2.  
  3. /* This includes <stdio.h> and "site.h".  */
  4. #include "w2c-ext.h"
  5.  
  6. extern unsigned char xord[], xchr[];
  7.  
  8. /* These help to deal with Pascal vs. C strings.  */
  9. void make_c_string (), make_pascal_string ();
  10. void end_with_null (), end_with_space ();
  11.  
  12.  
  13. /* Round R to the nearest whole number.  */
  14. integer zround (r)
  15.   double r;
  16. {
  17.   return r >= 0.0 ? (r + 0.5) : (r - 0.5);
  18. }
  19.  
  20.  
  21. /* Memory operations: variants of malloc(3) and realloc(3) that just
  22.    give up the ghost when they fail. It is a very bad practice to call 
  23.    system procs & not check for errors.
  24. */
  25.  
  26. extern char *malloc (), *realloc ();
  27.  
  28. char *xmalloc (size)
  29.   unsigned size;
  30. {
  31.   char *mem = malloc (size);
  32.   
  33.   if (mem == NULL)
  34.     {
  35.       fprintf (stderr, "! Cannot allocate %u bytes.\n", size);
  36.       exit (10);
  37.     }
  38.   
  39.   return mem;
  40. }
  41.  
  42.  
  43. char * xrealloc (ptr, size)
  44.   char *ptr;
  45.   unsigned size;
  46. {
  47.   char *mem = realloc (ptr, size);
  48.   
  49.   if (mem == NULL)
  50.     {
  51.       fprintf (stderr, "! Cannot reallocate %u bytes at %x.\n", size, ptr);
  52.       exit (10);
  53.     }
  54.     
  55.   return mem;
  56. }
  57.  
  58.  
  59. /* String operations.  */   
  60.    
  61. /* Deal with C and Pascal strings.  */
  62.  
  63. /* Change the Pascal string P_STRING into a C string; i.e., make it
  64.    start after the leading character Pascal puts in, and terminate it
  65.    with a null.  We also have to convert from the internal character set
  66.    (ASCII) to the external character set, if we're running on a
  67.    non-ASCII system.
  68. */ 
  69. void make_c_string (p_string)
  70.   char **p_string;
  71. {
  72.   (*p_string)++;
  73.   end_with_null (*p_string);
  74. }
  75.  
  76.  
  77. /* Replace the first space we come to with a null.
  78. */
  79. void end_with_null (s)
  80.  char *s;
  81. {
  82.   for ( ; *s != ' '; s++)
  83. #ifdef NONASCII
  84.     *s = xchr[*s]
  85. #endif
  86.     ;
  87.   *s = '\0';
  88. }
  89.  
  90.  
  91. /* Change the C string C_STRING into a Pascal string; i.e., make it
  92.    start one character before it does now (so C_STRING had better have
  93.    been a Pascal string originally), and terminate with a space.  We
  94.    also convert back from the external character set to the internal
  95.    character set (ASCII), if we're running on a non-ASCII system.
  96. */
  97. void make_pascal_string (c_string)
  98.   char **c_string;
  99. {
  100.   end_with_space (*c_string);
  101.   (*c_string)--;
  102. }
  103.  
  104. /* Replace the first null we come to with a space.
  105. */
  106. void end_with_space (s)
  107.   char *s;
  108. {
  109.   for ( ; *s != '\0' ; s++)
  110. #ifdef NONASCII
  111.     *s = xchr[*s]
  112. #endif
  113.     ;
  114.   
  115.   *s = ' ';
  116. }
  117.  
  118.  
  119. /* Change the suffix of BASE (a Pascal string) to be SUFFIX (another
  120.    Pascal string).  We have to change them to C strings to do the work,
  121.    then convert them back to Pascal strings.
  122. */
  123. void makesuffix (base, suffix)
  124.   char *base;
  125.   char *suffix;
  126. {
  127.   char *last_dot, *last_slash;
  128.   make_c_string (&base);
  129.   
  130.   last_dot = rindex (base, '.');
  131.   last_slash = rindex (base, '/');
  132.   
  133.   if (last_dot == NULL || last_dot < last_slash) /* Add the suffix?  */
  134.     {
  135.       make_c_string (&suffix);
  136.       strcat (base, suffix);
  137.       make_pascal_string (&suffix);
  138.     }
  139.     
  140.   make_pascal_string (&base);
  141. }
  142.  
  143.  
  144. /* Insert the string INSERTION into TARGET before the index WHERE.  We
  145.    assume that TARGET is large enough to hold the result.  
  146. */
  147. static void insert_string (target, where, insertion)
  148.   char target[];
  149.   int where;
  150.   char *insertion;
  151. {
  152.   int i;
  153.   unsigned insertion_length = strlen (insertion);
  154.   unsigned target_length = strlen (target);
  155.   
  156.   for (i = target_length; i >= where; i--)
  157.     target[i + insertion_length] = target[i];
  158.  
  159.   strncpy (target + where, insertion, insertion_length);
  160. }
  161.  
  162.  
  163.  
  164. /* Path searching. */
  165.  
  166. #define NUMBER_OF_PATHS 11
  167.  
  168. static char *path[NUMBER_OF_PATHS];
  169. static char *env_var_names[NUMBER_OF_PATHS]
  170.   = { "BIBINPUTS", "GFFONTS", "MFBASES", "MFINPUTS", "MFPOOL",
  171.       "PKFONTS", "TEXFORMATS", "TEXINPUTS", "TEXPOOL",
  172.       "TEXFONTS", "VFFONTS"
  173.     };
  174.  
  175. #define READ_ACCESS 4       /* Used in access(2) call.  */
  176.  
  177. /* What separates elements of the path variables.  */
  178. #ifdef MS_DOS
  179. #define PATH_DELIMITER ';'
  180. #else
  181. #define PATH_DELIMITER ':'
  182. #endif
  183.  
  184. /* We will need some system include files to deal with directories.  */
  185. #ifdef SEARCH_SUBDIRECTORIES
  186. #include <sys/types.h>
  187. #include <sys/stat.h>
  188. #ifdef SYSV
  189. #include <dirent.h>
  190. typedef struct dirent *directory_entry_type;
  191. #else
  192. #include <sys/dir.h>
  193. typedef struct direct *directory_entry_type;
  194. #endif /* not SYSV */
  195.  
  196. /* Declare getcwd(3).  */
  197. extern char *getcwd ();
  198. extern int errno;
  199. #endif /* SEARCH_SUBDIRECTORIES */
  200.  
  201.  
  202. /* Subroutines.  */
  203. static void next_component ();
  204. int is_dir ();
  205.  
  206. /* Says where NAME is ok to open for reading.  */
  207. #define READABLE_FILE(name) access (name, READ_ACCESS) == 0 && !is_dir (name)
  208.  
  209.  
  210. /* This routine initializes `path[PATH_INDEX]'.  If the environment
  211.    variable `env_var_names[PATH_INDEX]' is not set, we simply use 
  212.    DEFAULT_VALUE.  Otherwise, we use the value of the environment
  213.    variable, and then replace any ``extra'' colons with DEFAULT_VALUE. 
  214.  
  215.    For example, if DEFAULT_VALUE is `foo', and the environment variable
  216.    value is `:bar::baz:', the final result will be
  217.    `foo:bar:foo:baz:foo'.  (Of course, it is pointless to have more than
  218.    one extra `:' in practice, but the point is that it can be anywhere.)
  219.    
  220.    If subdirectory searching has been compiled (by defining
  221.    SEARCH_SUBDIRECTORIES), and SUBDIR_FLAG so indicates, we look at each
  222.    directory in the path and add all subdirectories we find to the end
  223.    of the path.  This is somewhat less efficient when we are looking for
  224.    only one file, and the file would be found early in the path, but is
  225.    far more efficient when we look up many files using the same path.  */
  226.  
  227. /* Values for SUBDIR_FLAG.  */
  228. #define SUBDIR_NO_CHECK 0
  229. #define SUBDIR_ALWAYS_CHECK 1
  230. #define SUBDIR_CHECK_IF_NOT_DEFAULT 2
  231.  
  232. static void
  233. do_path (path_index, default_value, subdir_flag)
  234.   unsigned path_index;
  235.   char *default_value;
  236.   int subdir_flag;
  237. {
  238.   char *temp;
  239.   char *the_path;
  240.  
  241.   temp = getenv (env_var_names[path_index]);
  242.   if (temp == NULL)
  243.     /* This doesn't actually assign into the array, but it doesn't
  244.        matter.  */
  245.     the_path = default_value;
  246.   else
  247.     { /* Replace extra `:'s with the system default.  */
  248.       the_path = xmalloc (strlen (temp) + 1);
  249.       strcpy (the_path, temp);
  250.       
  251.       if (*the_path == PATH_DELIMITER)
  252.         {
  253.           the_path = xrealloc (the_path, strlen (the_path) 
  254.                                          + strlen (default_value) + 1);
  255.           insert_string (the_path, 0, default_value);
  256.         }
  257.       if (*(the_path + strlen (the_path) - 1) == PATH_DELIMITER)
  258.         {
  259.           the_path = xrealloc (the_path, strlen (the_path)
  260.                                          + strlen (default_value) + 1);
  261.           strcat (the_path, default_value);
  262.         }
  263.       while ((temp = index (temp, PATH_DELIMITER)) != NULL)
  264.         {
  265.           temp++;
  266.           if (*temp == PATH_DELIMITER)
  267.             {
  268.               the_path = xrealloc (the_path, strlen (the_path)
  269.                                              + strlen (default_value) + 1);
  270.               insert_string (the_path, temp - the_path, default_value);
  271.               temp++;
  272.             }
  273.         }
  274.     }
  275.  
  276.   /* Assign to the final resting place.  */
  277.   path[path_index] = xmalloc (strlen (the_path) + 1);
  278.   strcpy (path[path_index], the_path);
  279.  
  280. #ifdef SEARCH_SUBDIRECTORIES
  281.   /* At this point, `path[path_index]' is the colon-separated list of
  282.      directories to search.  We want to add all the subdirectories
  283.      directly below each of those directories.  */
  284.   if (subdir_flag == SUBDIR_ALWAYS_CHECK
  285.       || (subdir_flag == SUBDIR_CHECK_IF_NOT_DEFAULT
  286.           && the_path != default_value))
  287.     {
  288.       DIR *dir;
  289.       directory_entry_type e;
  290.       char dirname[FILENAMESIZE];
  291.  
  292.       /* Unfortunately, we can't look in the environment for the current
  293.          directory, because if we are running under a program (let's say
  294.          Emacs), the PWD variable might have been set by Emacs' parent
  295.          to the current directory at the time Emacs was invoked.  This
  296.          is not necessarily the same directory the user expects to be
  297.          in.  So, we must always call getcwd(3), even though it is slow
  298.          and prone to hang in networked installations.  */
  299.       char *cwd = getcwd (NULL, FILENAMESIZE + 2);
  300.       if (cwd == NULL)
  301.         {
  302.           perror ("getcwd");
  303.           exit (errno);
  304.         }
  305.  
  306.       temp = xmalloc (strlen (path[path_index]) + 1);
  307.       strcpy (temp, path[path_index]);
  308.  
  309.       do
  310.         {
  311.           next_component (dirname, &temp);
  312.  
  313.           /* All the `::'s should be gone by now, but we may as well make
  314.              sure `opendir' doesn't crash.  */
  315.           if (*dirname == 0) continue;
  316.  
  317.           /* By changing directories, we save a bunch of string
  318.              concatenations (and make the pathnames the kernel looks up
  319.              shorter).  */
  320.           if (chdir (dirname) != 0) continue;
  321.           
  322.           dir = opendir (".");
  323.           if (dir == NULL) continue;
  324.  
  325.           while ((e = readdir (dir)) != NULL)
  326.             {
  327.               if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0
  328.                   && strcmp (e->d_name, "..") != 0)
  329.                 {
  330.                   unsigned len = strlen (path[path_index]);
  331.                   char potential[FILENAMESIZE];
  332.                   strcpy (potential, dirname);
  333.                   strcat (potential, "/");
  334.                   strcat (potential, e->d_name);
  335.  
  336.                   path[path_index] = xrealloc (path[path_index],
  337.                                                len + strlen (potential) + 2);
  338.  
  339.                   len = strlen (path[path_index]);
  340.                   *(path[path_index] + len) = PATH_DELIMITER;
  341.                   *(path[path_index] + len + 1) = 0;
  342.                   strcat (path[path_index], potential);
  343.                 }
  344.             }
  345.           closedir (dir);
  346.           
  347.           /* Change back to the current directory, in case the path
  348.              contains relative directory names.  */
  349.           if (chdir (cwd) != 0)
  350.             {
  351.               perror (cwd);
  352.               exit (errno);
  353.             }
  354.         }
  355.       while (*temp != 0);
  356.     }
  357. #endif
  358. }
  359.  
  360.  
  361. /* This sets up the paths, by either copying from an environment variable
  362.    or using the default path, which is defined as a preprocessor symbol
  363.    (with the same name as the environment variable) in `site.h'.  The
  364.    parameter PATH_BITS is a logical or of the paths we need to set.
  365. */
  366. extern void
  367. setpaths (path_bits)
  368.   int path_bits;
  369. {
  370.   /* We must assign to the TFM file path before doing any of the other
  371.      font paths, since it is used as a default.  */
  372.   if (path_bits
  373.       & (TFMFILEPATHBIT | GFFILEPATHBIT | PKFILEPATHBIT | VFFILEPATHBIT))
  374.     do_path (TFMFILEPATH, TEXFONTS, SUBDIR_ALWAYS_CHECK);
  375.  
  376.   if (path_bits & BIBINPUTPATHBIT)
  377.     do_path (BIBINPUTPATH, BIBINPUTS, SUBDIR_NO_CHECK);
  378.  
  379.   if (path_bits & GFFILEPATHBIT)
  380.     do_path (GFFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT);
  381.  
  382.   if (path_bits & MFBASEPATHBIT)
  383.     do_path (MFBASEPATH, MFBASES, SUBDIR_NO_CHECK);
  384.  
  385.   if (path_bits & MFINPUTPATHBIT)
  386.     do_path (MFINPUTPATH, MFINPUTS, SUBDIR_ALWAYS_CHECK);
  387.  
  388.   if (path_bits & MFPOOLPATHBIT)
  389.     do_path (MFPOOLPATH, MFPOOL, SUBDIR_NO_CHECK);
  390.  
  391.   if (path_bits & PKFILEPATHBIT)
  392.     do_path (PKFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT);
  393.  
  394.   if (path_bits & TEXFORMATPATHBIT)
  395.     do_path (TEXFORMATPATH, TEXFORMATS, SUBDIR_NO_CHECK);
  396.  
  397.   if (path_bits & TEXINPUTPATHBIT)
  398.     do_path (TEXINPUTPATH, TEXINPUTS, SUBDIR_ALWAYS_CHECK);
  399.  
  400.   if (path_bits & TEXPOOLPATHBIT)
  401.     do_path (TEXPOOLPATH, TEXPOOL, SUBDIR_NO_CHECK);
  402.  
  403.   if (path_bits & VFFILEPATHBIT)
  404.     do_path (VFFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT);
  405. }
  406.  
  407.  
  408. /* Look for NAME, a Pascal string, in a colon-separated list of
  409.    directories.  The path to use is given (indirectly) by PATH_INDEX.
  410.    If the search is successful, leave the full pathname in NAME (which
  411.    therefore must have enough room for such a pathname), padded with
  412.    blanks.  Otherwise, or if NAME is an absolute or relative pathname,
  413.    just leave it alone.
  414. */
  415. boolean
  416. testreadaccess (name, path_index)
  417.   char *name;
  418.   int path_index;
  419. {
  420.   char potential[FILENAMESIZE];
  421.   int ok = 0;
  422.   char *the_path = path[path_index];
  423.   char *saved_path = the_path;
  424.   
  425.   make_c_string (&name);
  426.  
  427.   if (*name == '/' || *name == '~'
  428.       || (*name == '.' && *(name + 1) == '/')
  429.       || (*name == '.' && *(name + 1) == '.' && *(name + 2) == '/'))
  430.     ok = READABLE_FILE (name); 
  431.   else
  432.     {
  433.       do
  434.     {
  435.       next_component (potential, &the_path);
  436.  
  437.           if (*potential != 0)
  438.             {
  439.               strcat (potential, "/");
  440.           strcat (potential, name);
  441.           ok = READABLE_FILE (potential);
  442.             }
  443.     }
  444.       while (!ok && *the_path != 0);
  445.  
  446.       /* If we found it, leave the answer in NAME.  */
  447.       if (ok)
  448.         strcpy (name, potential);
  449.     }
  450.   
  451.   make_pascal_string (&name);
  452.   
  453.   return ok;
  454. }
  455.  
  456.  
  457. /* Return, in NAME, the next component of PATH, i.e., the characters up
  458.    to the next PATH_DELIMITER.
  459. */
  460. static void next_component (name, path)
  461.   char name[];
  462.   char **path;
  463. {
  464.   unsigned count = 0;
  465.   
  466.   while (**path != 0 && **path != PATH_DELIMITER)
  467.     {
  468.       name[count++] = **path;
  469.       (*path)++; /* Move further along, even between calls.  */
  470.     }
  471.   
  472.   name[count] = 0;
  473.   if (**path == PATH_DELIMITER)
  474.     (*path)++; /* Move past the delimiter.  */
  475. }
  476.  
  477.  
  478.  
  479. /* Return true if FN is a directory or a symlink to a directory,
  480.    false if not.
  481. */
  482. int
  483. is_dir (fn)
  484.   char *fn;
  485. {
  486.   struct stat stats;
  487.  
  488.   return stat (fn, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR;
  489. }
  490.  
  491.  
  492.  
  493. /* File operations.  */
  494.  
  495. /* Open a file; don't return if any error occurs.  NAME is a Pascal
  496.    string, but is changed to a C string and not changed back.  
  497.    RMD: I do want it changed back
  498. */ 
  499. FILE * checked_fopen (name, mode)
  500.   char *name;
  501.   char *mode;
  502. {
  503.   FILE *result;
  504.   char *cp;
  505.  
  506.   make_c_string (&name);
  507.   
  508.   result = fopen (name, mode);
  509.   if (result != NULL) {
  510.     make_pascal_string (&name);
  511.     return result;}
  512.     
  513.   perror (name);
  514.   exit (1);
  515.   /*NOTREACHED*/
  516. }
  517.  
  518.  
  519. /* Return true if we're at the end of FILE, else false.  This implements
  520.    Pascal's `eof' builtin.
  521. */
  522. boolean test_eof (file) 
  523.   text file;
  524. {
  525.   register int c;
  526.   FILE *ff ;
  527.   /* Maybe we're already at the end?  */
  528.   ff = *file ;
  529.   if (feof( ff))
  530.     return true;
  531.  
  532.   if ((c = getc (*file)) == EOF)
  533.     return true;
  534.  
  535.   /* Whoops, we weren't at the end.  Back up.  */
  536.   (void) ungetc (c, *file);
  537.  
  538.   return false;
  539. }
  540.  
  541.  
  542. /* Return true on end-of-line in FILE or at the end of FILE, else false.
  543. */
  544.  
  545. boolean eoln (file)
  546.   text file;
  547. {
  548.   register int c;
  549.  
  550.   if (feof (*file))
  551.     return true;
  552.   
  553.   c = getc (*file);
  554.   
  555.   if (c != EOF)
  556.     (void) ungetc (c, *file);
  557.     
  558.   return c == '\n' || c == EOF;
  559. }
  560.  
  561.  
  562. /* Print real number R in the Pascal format N:M on the file F.
  563. RMD: these procs not used; I made web2c generate proper write statements.
  564. */
  565. void fprintreal (f, r, n, m)
  566.   text f;
  567.   double r;
  568.   int n, m;
  569. {
  570.   char fmt[50];  /* Surely enough, since N and M won't be more than 25
  571.                     digits each!  */
  572.  
  573.   (void) sprintf (fmt, "%%%d.%dlf", n, m);
  574.   (void) fprintf (*f, fmt, r);
  575. }
  576.  
  577.  
  578. /* Print S, a Pascal string, on the file F.  It starts at index 1 and is
  579.    terminated by a space.
  580. */
  581. static void fprint_pascal_string (s, f)
  582.   char *s;
  583.   FILE *f;
  584. {
  585.   s++;
  586.   while (*s != ' ') putc (*s++, f);
  587. }
  588.  
  589. /* Print S, a Pascal string, on stdout.
  590. */
  591. void printpascalstring (s)
  592.   char *s;
  593. {
  594.   fprint_pascal_string (s, stdout);
  595. }
  596.  
  597. /* Ditto, for stderr.
  598. */
  599. void errprintpascalstring (s)
  600.   char *s;
  601. {
  602.   fprint_pascal_string (s, stderr);
  603. }
  604.  
  605. /* Read an integer from the file F, reading past the subsequent end of
  606.    line.
  607. */
  608. integer inputint (f)
  609.   text f;
  610. {
  611.   char buffer[50]; /* Long enough for anything reasonable.  */
  612.  
  613.   return
  614.     fgets (buffer, sizeof (buffer), *f)
  615.     ? atoi (buffer)
  616.     : 0;
  617. }
  618.  
  619. /* Read three integers from stdin.
  620. */
  621. void zinput3ints (a,b,c)
  622.   integer *a, *b, *c;
  623. {
  624.   while (scanf ("%ld %ld %ld\n", a, b, c) != 3)
  625.     (void) fprintf (stderr, "Please enter three integers.\n");
  626. }
  627.  
  628.  
  629.